package com.cn.demo.controller;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cn.demo.config.*;
import com.cn.demo.entity.SeckillGoods;
import com.cn.demo.entity.SeckillOrder;
import com.cn.demo.service.OrderService;
import com.cn.demo.service.SeckillService;
import com.cn.demo.util.R;
import com.cn.demo.util.RequestResultCode;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 秒杀接口类
 *
 * @author wangjf
 * @version 1.0
 * @createDate 2019/11/14 16:36
 * @projectName test
 */
@Slf4j
@RestController
@RequestMapping("/seckill")
public class SeckillController {

    @Autowired
    private SeckillRRateLimiter seckillRRateLimiter;
    @Autowired
    private SeckillUserMapCache seckillUserMapCache;
    @Autowired
    private SeckillLockUserCache seckillLockUserCache;
    @Autowired
    private SeckillQueueFactory seckillQueueFactory;
    @Autowired
    private SeckillService seckillService;
    @Autowired
    private OrderService orderService;

    /**
     * 拓展秒杀
     * @author: wangjf
     * @createTime: 2019/11/21 14:45
     * @param queueId 活动ID
     * @param userId
     * @return com.cn.demo.util.R<java.lang.String>
     */
    @PostMapping("/ex/{queueId}/{userId}")
    public R<String> seckillEx(@PathVariable("queueId") String queueId, @PathVariable("userId") String userId) {

        log.info("用户userid={},想秒杀queueId={}", userId, queueId);
        //判断秒杀状态，只有在进行中的可以秒杀
        int seckillStatus = seckillQueueFactory.getStatus(queueId);
        if (seckillStatus != RequestResultCode.SECKILL_DOING.getErrorCode()) {
            log.error("userId={},活动状态={}", userId, seckillStatus);
            return R.failed(RequestResultCode.getErrorMessage(seckillStatus));
        }
        //接口限流
        //没有可用令牌，直接返回给前端，秒杀失败，可以重试，抢过的不能重试
        if (!seckillRRateLimiter.tryAcquire()) {
            log.error("令牌已用完,秒杀失败 userId={},queueId={}", userId, queueId);
            return R.failed("秒杀失败,请10秒后重试");
        }

        //消费令牌
        seckillRRateLimiter.acquire();

        String queueIdUserId = queueId + "_" + userId;

        //秒杀成功了，不能重复秒杀
        if (seckillLockUserCache.existKey(queueIdUserId)) {
            log.error("userId={} 不能重复秒杀，queueId={}", userId, queueId);
            return R.failed(RequestResultCode.SECKILL_REPEAT);
        }

        if (seckillUserMapCache.existKey(queueIdUserId)) {
            log.error("userId={} 手太快,请10秒后重试queueId={}", userId, queueId);
            return R.failed(RequestResultCode.SECKILL_FAST);
        }
        seckillUserMapCache.put(queueIdUserId);

        RQueue<SeckillGoods> queue = seckillQueueFactory.getQueue(queueId);
        if (queue == null) {
            return R.failed(RequestResultCode.SECKILL_NOT_EXIST);
        }
        //秒杀商品
        SeckillGoods goods = queue.poll();
        if (goods == null) {
            log.error("秒杀活动已结束，userId={},queueId={}", userId, queueId);
            return R.failed(RequestResultCode.SECKILL_FINISH);
        }
        //秒杀成功
        String goodsId = seckillService.seckillGoods(goods, userId,queueId);
        return R.ok(goodsId, RequestResultCode.SUCCESS);
    }


    /**
     * 查询订单是否生成，由前端10秒发起一次查询请求
     *
     * @param userId
     * @return com.cn.demo.util.R<java.lang.String>
     * @author: wangjf
     * @createTime: 2019/11/15 17:17
     */
    @GetMapping("/{queueId}/{userId}")
    public R<String> queryOrderStatus(@PathVariable("queueId") String queueId,@PathVariable("userId") String userId) {

        String queueIdUserId = queueId + "_" + userId;
        if (!seckillLockUserCache.existKey(queueIdUserId)) {
            return R.failed(RequestResultCode.SECKILL_NOT_EXIST);
        }

        List<SeckillOrder> select = orderService.select(Wrappers.<SeckillOrder>query().lambda().eq(SeckillOrder::getUserId, userId).eq(SeckillOrder::getQueueId,queueId));
        if (CollectionUtils.isEmpty(select)) {
            return R.failed(RequestResultCode.SECKILL_QUEUE);
        }
        return R.ok(RequestResultCode.SECKILL_PAY);
    }


    /**
     * 订单支付
     *
     * @param orderNo
     * @return com.cn.demo.util.R<java.lang.String>
     * @author: wangjf
     * @createTime: 2019/11/15 17:29
     */
    @PostMapping("/pay/{orderNo}")
    public R<String> payOrder(@PathVariable("orderNo") String orderNo) {

        List<SeckillOrder> select = orderService.select(Wrappers.<SeckillOrder>query().lambda().eq(SeckillOrder::getOrderNo, orderNo));

        if (CollectionUtils.isEmpty(select)) {
            return R.failed("订单不存在");
        }

        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setId(select.get(0).getId());
        seckillOrder.setStatus(1);
        int i = orderService.updateById(seckillOrder);
        if (i == 1) {
            return R.ok("订单支付成功");
        }
        return R.failed("订单支付失败");
    }

    /**
     * 通过订单编号查询订单状态
     *
     * @param orderNo
     * @return com.cn.demo.util.R<java.lang.String>
     * @author: wangjf
     * @createTime: 2019/11/18 15:20
     */
    @GetMapping("/pay/{orderNo}")
    public R<String> queryPay(@PathVariable("orderNo") String orderNo) {

        List<SeckillOrder> select = orderService.select(Wrappers.<SeckillOrder>query().lambda().eq(SeckillOrder::getOrderNo, orderNo));

        if (CollectionUtils.isEmpty(select)) {
            return R.failed("订单不存在");
        }

        if (select.get(0).getStatus() == 1) {
            return R.ok("订单已支付");
        }

        return R.ok("订单未支付");
    }


}
